package com.lyf.aop;

import com.lyf.annotation.CacheRefresh;
import com.lyf.redis.RedisUtil;
import com.lyf.service.CacheRefreshService;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.Arrays;


/**
 * @author hailin.
 * @date 2020/9/8 17:33
 **/
@Order(3)
@Aspect
@Component
@Slf4j
public class CacheRefreshAspect {
    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    private CacheRefreshService cacheRefreshService;

    @Around("@annotation(com.lyf.annotation.CacheRefresh) && @annotation(cacheRefresh)")
    public Object process(ProceedingJoinPoint pjp, CacheRefresh cacheRefresh) throws Throwable {
        //获取类信息
        Class<?> targetCls = pjp.getTarget().getClass();
        //获取方法签名
        MethodSignature methodSignature = (MethodSignature) pjp.getSignature();
        //获取目标方法
        Method targetMethod = targetCls.getDeclaredMethod(methodSignature.getName(), methodSignature.getParameterTypes());
        //获取执行参数
        Object[] args = pjp.getArgs();

        String cacheName = cacheRefresh.value();
        String fullKey = String.format("%s::%s", cacheName, keyGenerator(targetCls, targetMethod, args));
        Object o = redisUtil.get(fullKey);
        if (o != null) {
            //异步更新缓存
            cacheRefreshService.updateCache(fullKey, pjp, cacheRefresh);
            return o;
        }
        Object proceed = pjp.proceed();
        //异步添加缓存
        cacheRefreshService.addCache(fullKey, proceed, cacheRefresh);// 永久
        return proceed;
    }

    /**
     * 生成主键规则
     */
    private String keyGenerator(Class cls, Method method, Object[] params) {
        StringBuilder sb = new StringBuilder();
        sb.append(cls.getName());
        sb.append(".");
        sb.append(method.getName());
        // 去除冒号: 反斜杠\ 双引号" 单引号' 空格
        sb.append(Arrays.toString(params).replaceAll("[\\\"' ]", ""));
        return sb.toString();
    }
}
